﻿using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;

namespace SIMcSDK
{
    //public delegate void Volaju(int callId, StringBuilder sturi);
    
    public delegate void OnCallStateChanged(int callId, int stateId);
    public delegate void OnCallIncoming(int callId, StringBuilder number);
    public delegate void OnCallHoldConfirm(int callId);
    public delegate void OnDtmfDigit(int callId, int digit);

    public class CallControl
    {
        #region DLL declarations
        // call API
        [DllImport("pjsipDll.dll")]
        private static extern int dll_makeCall(int accountId, string uri);
        [DllImport("pjsipDll.dll")]
        private static extern int dll_releaseCall(int callId);
        [DllImport("pjsipDll.dll")]
        private static extern int dll_answerCall(int callId, int code);
        [DllImport("pjsipDll.dll")]
        private static extern int dll_holdCall(int callId);
        [DllImport("pjsipDll.dll")]
        private static extern int dll_retrieveCall(int callId);
        [DllImport("pjsipDll.dll")]
        private static extern int dll_xferCall(int callId, string uri);
        [DllImport("pjsipDll.dll")]
        private static extern int dll_xferCallWithReplaces(int callId, int dstSession);
        [DllImport("pjsipDll.dll")]
        private static extern int dll_serviceReq(int callId, int serviceCode, string destUri);
        [DllImport("pjsipDll.dll")]
        private static extern int dll_dialDtmf(int callId, string digits, int mode);
        [DllImport("pjsipDll.dll")]
        private static extern int dll_sendInfo(int callid, string content);

        #endregion DLL declarations

        #region Callback declarations
        // Callback function registration declarations 
        // passing delegate to unmanaged code (.dll)
        [DllImport("pjsipDll.dll")]
        private static extern int onCallStateCallback(OnCallStateChanged cb);
        [DllImport("pjsipDll.dll")]
        private static extern int onCallIncoming(OnCallIncoming cb);
        [DllImport("pjsipDll.dll")]
        private static extern int onCallHoldConfirmCallback(OnCallHoldConfirm cb);
        [DllImport("pjsipDll.dll")]
        private static extern int onDtmfDigitCallback(OnDtmfDigit cb);


        // Static declaration because of CallbackonCollectedDelegate exception!
        static OnCallStateChanged csDel = new OnCallStateChanged(onCallStateChanged);
        static OnCallIncoming ciDel = new OnCallIncoming(onCallIncoming);
        static OnCallHoldConfirm chDel = new OnCallHoldConfirm(onCallHoldConfirm);
        static OnDtmfDigit dtDel = new OnDtmfDigit(onDtmfDigit);

        public static event OnCallStateChanged CallStateChanged;
        public static event OnCallIncoming CallIncoming;
        public static event OnCallHoldConfirm CallHoldConfirm;
        public static event OnDtmfDigit DtmfDigit;

        #endregion Callback declarations

        #region Callbacks

        /// <summary>
        /// 
        /// </summary>
        /// <param name="callId"></param>
        /// <param name="callState"></param>
        /// <returns></returns>
        private static void onCallStateChanged(int callId, int callState)
        {
            if (null != CallStateChanged) CallStateChanged(callId, callState);            
            return;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="callId"></param>
        /// <param name="sturi"></param>
        /// <returns></returns>
        private static void onCallIncoming(int callId, StringBuilder sturi)
        {
            if (null != CallIncoming) CallIncoming(callId, sturi);
            return;
        }

        /// <summary>
        /// Not used
        /// </summary>
        /// <param name="callId"></param>
        /// <returns></returns>
        private static void onCallHoldConfirm(int callId)
        {
            if (null != CallHoldConfirm) CallHoldConfirm(callId);
            return;
        }

        /// <summary>
        /// Not used
        /// </summary>
        /// <param name="callId"></param>
        /// <returns></returns>
        private static void onDtmfDigit(int callId, int digit)
        {
            if (null != DtmfDigit) DtmfDigit(callId, digit);
            return;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Static initializer. Call this method to set callbacks from SIP stack. 
        /// </summary>
        public static void initialize()
        {
            // assign callbacks
            onCallIncoming(ciDel);
            onCallStateCallback(csDel);
            onCallHoldConfirmCallback(chDel);
            onDtmfDigitCallback(dtDel);
        }

        /// <summary>
        /// Update registration status
        /// </summary>
        /// <param name="dialedNo">uri na ktoru chcem zavolat (vratane sip:)</param>
        /// <param name="accountId">ID zaregistrovaneho uctu</param>
        public static int makeCall(string dialedNo, int accountId)
        {
            //string hostname = "192.168.1.1";
            //string uri = "sip:" + dialedNo + "@" + hostname;
            //MessageBox.Show("pred dll_makecall");
            int sessionId = dll_makeCall(accountId, dialedNo);
            //MessageBox.Show("po dll_makecall");
            return sessionId;
        }

        public static bool endCall(int sessionId)
        {
            dll_releaseCall(sessionId);
            return true;
        }

        public static bool alerted(int sessionId)
        {
            dll_answerCall(sessionId, 180);
            return true;
        }

        public static bool acceptCall(int sessionId)
        {
            dll_answerCall(sessionId, 200);
            return true;
        }

        public static bool holdCall(int sessionId)
        {
            dll_holdCall(sessionId);
            return true;
        }

        public static bool retrieveCall(int sessionId)
        {
            dll_retrieveCall(sessionId);
            return true;
        }

        public static bool xferCall(int sessionId, string number)
        {
            string hostname = "192.168.1.1";
            string uri = "sip:" + number + "@" + hostname;
            dll_xferCall(sessionId, uri);
            return true;
        }

        public static bool xferCallSession(int sessionId, int session)
        {
            dll_xferCallWithReplaces(sessionId, session);
            return true;
        }

        public static bool threePtyCall(int sessionId, int session)
        {
            dll_serviceReq(sessionId, 18, "");
            return true;
        }

        public static bool serviceRequest(int sessionId, int code, string dest)
        {
            string hostname = "192.168.1.1";
            string destUri = "<sip:" + dest + "@" + hostname + ">";
            dll_serviceReq(sessionId, (int)code, destUri);
            return true;
        }

        public static bool dialDtmf(int sessionId, string digits, int mode)
        {
            // todo:::check the dtmf mode
            if (mode == 0)
            {
                dll_dialDtmf(sessionId, digits, mode);
            }
            else
            {
                dll_sendInfo(sessionId, digits);
            }
            return true;
        }
        #endregion Methods

    }
}
